import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Like } from 'typeorm';
import { BusinessException } from '~/common/exceptions/biz.exception';
import { ErrorEnum } from '~/constants/error-code.constant';
import { paginate } from '~/helper/paginate';
import { Pagination } from '~/helper/paginate/pagination';
import { TodoEntity } from '~/modules/todo/todo.entity';
import { ExcelService } from '../tools/excel/excel.service';
import { ToDoConstants } from './todo.service.type';
import { isEmpty } from 'lodash';
import * as xlsx from 'xlsx-js-style';

import {
  TodoDto,
  TodoQueryDto,
  TodoUpdateDto,
  FileDataSaveDto,
} from './todo.dto';
import { empty } from 'rxjs';

@Injectable()
export class TodoService {
  constructor(
    @InjectRepository(TodoEntity)
    private todoRepository: Repository<TodoEntity>,
    private _excelService: ExcelService
  ) {}

  async list({
    page,
    pageSize,
    value,
  }: TodoQueryDto): Promise<Pagination<TodoEntity>> {
    const queryBuilder = this.todoRepository.createQueryBuilder('todo').where({
      ...(value && { value: Like(`%${value}%`) }),
    });

    return paginate(queryBuilder, { page, pageSize });
  }

  async detail(id: number): Promise<TodoEntity> {
    const item = await this.todoRepository.findOneBy({ id });
    if (!item) throw new NotFoundException('未找到该记录');

    return item;
  }

  async create(dto: TodoDto) {
    await this.todoRepository.save(dto);
  }

  async update(id: number, dto: TodoUpdateDto) {
    await this.todoRepository.update(id, dto);
  }
  async delete(id: number) {
    const item = await this.detail(id);

    await this.todoRepository.remove(item);
  }

  async excelExport() {
    const headers = Object.keys(ToDoConstants.ToDoMap);
    const fields = Object.values(ToDoConstants.ToDoMap);

    const value = '';

    const todos = await this.todoRepository
      .createQueryBuilder('todo')
      .select(fields)
      .where('todo.value LIKE :value', { value: `%${value}%` })
      .getRawMany();

    // 这块获取到数据后，可以把数据二次处理，比如将其根据字典转化，字段重新赋值等
    const resultData = todos.map(item => {
      return {
        ...item,
        todo_status: item.todo_status === 0 ? '未完成' : '已完成',
      };
    });
    // 输出示例数据{  todo_value: '2', todo_status: 1}

    const url = await this._excelService.createStyledExcel(
      headers,
      resultData,
      'ToDo数据.xlsx'
    );
    return url;
  }

  async ExcelImportCheckData(file: Express.Multer.File) {
    if (!file) {
      throw new BusinessException(ErrorEnum.INVALID_FILE);
    }

    // 将 MultipartFile 转换为 Buffer
    const buffer = await file.buffer;

    // 使用 xlsx 读取 Excel 文件
    const workbook = xlsx.read(buffer, {
      type: 'buffer',
      cellStyles: true,
      raw: true,
    });

    // 假设我们只处理第一个工作表
    const sheetName = workbook.SheetNames[0];
    const worksheet = workbook.Sheets[sheetName];

    // 将工作表转换为 JSON 格式
    const jsonData = xlsx.utils.sheet_to_json(worksheet, {
      header: 1,
      raw: true,
    });

    // 判断jsonData是否为空对象
    if (isEmpty(jsonData) || jsonData.length === 1) {
      throw new BusinessException(ErrorEnum.FILE_DATA_EMPTY);
    }

    const requiredIndices = [0]; // 不为空的下标索引
    const dateIndices = []; // 时间格式下标索引数组
    const dictionaryIndices = [1]; // 字典类型下标数组

    // 进行数据检查
    const error = await this.checkExcelData(
      jsonData.slice(1),
      jsonData[0],
      requiredIndices,
      dateIndices,
      dictionaryIndices
    );
    // 校验error是否为空 或者 error.length>0
    if (error.length > 0) {
      return { msg: '数据校验失败', error };
    } else {
      return {
        msg: '数据校验成功',
        jsonData: jsonData.slice(1),
      };
    }
  }

  async ExcelImportSaveData(data) {
    if (isEmpty(data.jsonData)) {
      throw new BusinessException(ErrorEnum.DATA_EMPTY);
    }
    const result = await this.assembleInitialData(data.jsonData);

    await this.todoRepository.save(result);
    return { mag: '导入成功' };
  }

  // 处理数据成可插入数据库的格式
  async assembleInitialData(jsonData) {
    const fieldNames = ['value', 'status'];
    const dataList = [];

    const promises = jsonData.map(async item => {
      if (isEmpty(item)) {
        return;
      }
      const info = {};
      for (let i = 0; i < fieldNames.length; i++) {
        if (fieldNames[i] == 'status') {
          info[fieldNames[i]] = item[i] == '已完成' ? true : false;
        } else {
          info[fieldNames[i]] = item[i];
        }
      }
      return info;
    });
    const resolvedData = await Promise.all(promises);
    resolvedData.forEach(item => {
      if (item) {
        dataList.push(item);
      }
    });
    return dataList;
  }

  // 检查表格数据
  async checkExcelData(
    jsonData,
    title,
    requiredIndices,
    dateIndices,
    dictionaryIndices
  ) {
    const errors = [];
    // jsonData中移除 空的数组
    jsonData = jsonData.filter(item => {
      if (item.length === 0) {
        return false;
      }
      return true;
    });
    if (jsonData.length > 0) {
      // 对原始数据进行格式校验
      for (let i = 0; i < jsonData.length; i++) {
        const item = jsonData[i];
        const currentErrors = [];
        // 校验不为空的字段
        for (const index of requiredIndices) {
          if (!this.isRequired(item[index])) {
            currentErrors.push(`${title[index]}不能为空`);
          }
        }

        // 校验时间格式的字段
        for (const index of dateIndices) {
          const dateString = item[index];
          if (dateString && !this.isValidDate(dateString)) {
            currentErrors.push(`${title[index]} 字段日期格式不正确`);
          }
        }

        // 校验字典类型的字段
        for (const index of dictionaryIndices) {
          const value = item[index];
          const type = title[index];
          if (!(await this.isValidDictionaryValue(value, type))) {
            currentErrors.push(`${title[index]}字段中在字典表中不存在`);
          }
        }

        if (currentErrors.length > 0) {
          errors.push({ row: i + 2, errors: currentErrors });
        }
      }
    }

    return errors;
  }
  isRequired(value: any): boolean {
    if (value === null || value === undefined || value === '') {
      return false;
    }
    return true;
  }

  isValidDate(dateString: string): boolean {
    // 校验是否是 yyyy-MM-dd 时间格式
    const regex = /^\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[12]\d|3[01])$/;
    return regex.test(dateString);
  }

  async isValidDictionaryValue(value: string, type: string) {
    let dictionList;
    if (type === '状态') {
      dictionList = [
        {
          dictKey: 'DICT_TODO_STATUS',
          dictValue: [
            {
              dictCode: 'DICT_TODO_STATUS',
              itemName: '未完成',
              itemCode: false,
            },
            {
              dictCode: 'DICT_TODO_STATUS',
              itemName: '已完成',
              itemCode: true,
            },
          ],
        },
      ];
    }

    if (!dictionList || !dictionList[0].dictValue) {
      return false;
    }

    const exists = dictionList[0].dictValue.some(
      item => item.itemName === value
    );
    return exists;
  }
}
